home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * Printing.C *
- * *
- * Line Printer Daemon using TCP/IP printer protocol *
- * *
- * -------------- The printing routines -------------- *
- * *
- * Written by Casper Boon, April, 1992. *
- * *
- * © 1992, Casper Boon. *
- * *
- * With thanks to Mike Schuster whose article in MacTutor showed how to *
- * access the PAP code in the LaserWriter. Also thanks to the CAP team *
- * at for their PAP code and printer access code. *
- * *
- * This file contains routines for communicating with the printer using *
- * the Printer Access Protocol (PAP) as well as routines for sending *
- * a file to a serial printer. The PAP communication is bi-directional *
- * allowing results to be returned from the printer as well as data *
- * being sent to the printer. Serial is on uni-directional so no info *
- * can be returned. This is one obvious possible improvement. *
- * *
- * The mechanism in both cases is to request for opening the printer, *
- * using backgrounder to install a task when connection is made. Then *
- * a buffer is filled from the file and written to the printer async- *
- * ronously using backgrounder to call the task repeatedly on completion*
- * to load and send the next buffer until the end of file is reached. *
- * In the case of the PAP connection a second set of tasks is begun to *
- * read from the PAP connection until an eond-of-file is received. The *
- * PAP printing is complete when the end-of-file is received. The serial*
- * printing is complete when the end of file is read in the print file *
- * and the last buffer has been sent. *
- * *
- * The accounting is done only for the PAP printer by sending the page *
- * count request before starting the print file and reading the result *
- * from the printer. This is repeated at the end of the print file *
- * before sending the end-of-file. The difference between the results *
- * should be the number of pages printed. The only problem is that if *
- * a print error occurs the printer ignores the rest of the print file *
- * until the end of file so in this case we need to send the accounting *
- * request after closing the connection so that we can still get the *
- * number of pages printed before the error occured. This is where the *
- * EndPage errors come from. *
- * *
- * One other possible enhancement is to add support for SCSI printers. *
- * *
- ************************************************************************/
-
- /* include these header files for the types and vars */
- #include "LPD.H"
- #include "PAP.H"
- #include "lpdProtos.H"
- #include "BackGrounder.H"
-
-
-
- #define F_BUFF_SIZE 4096 /* size of the file read buffer, we send this */
- /* much to the laser printer so it must be */
- /* <= flow_quantum*512 and flow quantum for */
- /* the laser writer is 8 so we make it 4K */
- #define SPIN_TIME 20
-
-
- typedef struct {
- LongInt prt_bytes; /* number of bytes printed */
- char rbuff[512]; /* read buffer */
- char xbuff[F_BUFF_SIZE]; /* file buffer */
- integer rsize; /* PAP read size */
- integer rstate; /* Status of PAPRead */
- integer wstate; /* Status of PAPWrite */
- integer ostate; /* Status of PAPOpen */
- integer *prtstate; /* Pointer to status of print... */
- integer reof; /* Set to PAP read EOF status */
- integer feof; /* Set when on EOF of print file */
- integer weof; /* true when the eof is sent to the printer */
- PAPStatusRec status; /* pap status */
- integer pfRef; /* print file reference number */
- integer prefnum; /* pap refNum */
- Handle entity; /* Handle to locked entity name */
- Handle elog; /* the error log handle */
- integer count; /* number of bytes to read from print file */
- integer last_error; /* the last recorded error */
- LongInt prt_size; /* size of print file */
- LongInt startpages; /* page count before printing file */
- LongInt endpages; /* page count after printing file */
- Ptr read_task;
- Boolean killed;
- Boolean postscript;
- } PassBlock, *PassPtr;
-
-
-
-
- void KillPrinting(integer result, PassPtr passer);
- static void DonePrinting(integer result, PassPtr passer);
- static void OpenCallBack(integer o_state, Ptr param);
- static void WriteCallBack(integer w_state, Ptr param);
- static void ReadCallBack(integer w_state, Ptr param);
- static void WEOFCallBack(integer r_state, Ptr param);
- static void REOFCallBack(integer r_state, Ptr param);
-
- static StringPtr PrErrorStatus(Handle entity);
- static StringPtr PrForceStatus(Handle entity);
- static void LogPrErrorStatus(Handle entity);
- static StringPtr PrStatus(Handle entity);
- static Handle GenerateEntity(StringPtr printer);
- static LongInt ReadPageCount(char *s);
- static void ReadProcess(PassPtr passer);
- static void GetEndPages(PassPtr passer);
-
- static char *account_str =
- "(%[ pagecount: ) print statusdict begin pagecount end 20 string cvs print ( ]%\n) print flush\n";
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void PAPDownLoad(integer xRef, Boolean postscript,
- StringPtr printer, Handle elog, integer *pstate)
- {
- integer prErr, pres;
- PassPtr passer = (PassPtr)NewPtrClear(sizeof(PassBlock));
-
- stopped = FALSE;
-
- passer->reof = FALSE;
- passer->feof = FALSE;
- passer->weof = FALSE;
- passer->pfRef = -1;
- passer->prefnum = -1;
- passer->count = 0;
- passer->last_error = 0;
- passer->read_task = NIL;
- passer->killed = FALSE;
- passer->prtstate = pstate;
- passer->last_error = 0;
- passer->entity = NIL;
- passer->elog = elog;
- passer->startpages = -1;
- passer->endpages = -1;
- *pstate = 1;
-
- passer->prt_bytes = 0L;
- GetEOF(xRef, &passer->prt_size);
-
- passer->pfRef = xRef; /* save the reference number globally */
- if (debugOn)
- log_printf("new print file (%d) size %ld\n", passer->pfRef, passer->prt_size);
-
- passer->prefnum = -1; /* No connection */
- passer->rstate = 0;
- passer->wstate = 0; passer->ostate = 0; /* initial states */
- passer->postscript = postscript;
-
- if (passer->entity = PAPLoad())
- {
- if ( printer )
- passer->entity = GenerateEntity(printer);
- else
- HandToHand(&passer->entity);
- HLock(passer->entity);
-
- if (debugOn)
- log_printf("Looking for LaserWriter \"%p:%p@%p\"\n",
- *passer->entity,
- *passer->entity+((*passer->entity)[0]+1),
- *passer->entity+((*passer->entity)[0]+1)+((*passer->entity)[((*passer->entity)[0]+1)]+1));
-
- POPEN_Banner_Up((StringPtr)*(passer->entity), PrForceStatus(passer->entity));
-
- OpenCallBack(-4096, (Ptr)passer); /* will insert itself in the wait queue */
- }
- else
- {
- log_printf("Cannot Load PAP\n");
- DonePrinting(pres = openErr, passer);
- }
- }
-
- /************************************************************************
- * *
- * Given a pascal string of the form "\pname@LaserWriter:zone" we *
- * generate a locked EntityName handle for it *
- * *
- ************************************************************************/
- Handle GenerateEntity(StringPtr printer)
- {
- Byte *prt, *ent, old_len, i, j;
- Handle entity;
-
- old_len = printer[0];
- prt = printer;
-
- if ( !(entity = NewHandleClear( sizeof(EntityName) )) )
- return NIL;
-
- HLock(entity);
- ent = (Byte*)*entity;
-
- i = 1; j = 1; prt++;
- while ( (i++ <= old_len) && (*prt != '@') && (*prt != ':') )
- ent[j++] = *prt++;
-
- ent[0] = j - 1; ent += j;
-
- if (*prt != ':' || i > old_len)
- {
- BlockMove("\pLaserWriter", ent, 12);
- ent += 12;
- }
- else
- {
- j = 1; prt++;
- while ( (i++ <= old_len) && (*prt != '@') )
- ent[j++] = *prt++;
-
- ent[0] = j - 1; ent += j;
- }
-
- if (i > old_len)
- BlockMove("\p*", ent, 2);
- else
- {
- j = 1; prt++;
- while (i++ <= old_len)
- ent[j++] = *prt++;
- ent[0] = j - 1;
- }
-
- if (debugOn)
- {
- log_printf("Generated entity \"%p:%p@%p\" for \"%p\"\n",
- *entity,
- *entity+((*entity)[0]+1),
- *entity+((*entity)[0]+1)+((*entity)[((*entity)[0]+1)]+1),
- printer);
- }
-
- return entity;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void KillPrinting(integer result, PassPtr passer)
- {
- stopped = FALSE;
-
- if (passer->killed) /* we have already been killed once, abort now */
- return;
-
- log_printf("Print killed......\n");
- passer->last_error = result;
- passer->feof = TRUE;
- passer->killed = TRUE;
-
- if (passer->ostate == noErr)
- {
- PAPClose(passer->prefnum);
- passer->ostate = -1; /* no longer open */
- }
- passer->reof = TRUE;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void GetEndPages(PassPtr passer)
- {
- OSErr err;
-
- if (!passer->postscript || !accounting) return;
-
- do {
- passer->ostate = 1;
- err = PAPOpen(&passer->prefnum, (EntityPtr)*passer->entity, 1,
- &passer->status, &passer->ostate);
- if (err != noErr)
- passer->ostate = err;
-
- WaitForState(&passer->ostate);
- }
- while ( passer->ostate == -4096 );
-
- if (passer->ostate < 0)
- {
- log_printf("GetEndPages error %d\n", passer->ostate);
- return; /* give up */
- }
-
- PAPWrite(passer->prefnum, account_str, strlen(account_str), 1, &passer->wstate);
- WaitForState(&passer->wstate);
-
- passer->rstate = 1;
- do {
- PAPRead(passer->prefnum, passer->rbuff, &passer->rsize, &passer->reof, &passer->rstate);
-
- WaitForState(&passer->rstate);
-
- ReadProcess(passer);
- }
- while (!passer->reof);
-
- PAPClose(passer->prefnum);
- }
-
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void DonePrinting(integer result, PassPtr passer)
- {
- if (result > 0) result = 0;
-
- if (passer->entity)
- {
- HUnlock(passer->entity);
- if (passer->ostate == noErr)
- {
- PAPClose(passer->prefnum);
- if (passer->endpages < 0)
- GetEndPages(passer);
- }
- }
-
- PRT_Banner_Down(); /* will do both (same thing) */
-
- if (passer->endpages > 0)
- log_printf("printed %ld pages\n", passer->endpages-passer->startpages);
- else if (passer->ostate == noErr)
- log_printf("print aborted, couldn't endpage\n");
- // else
- // log_printf("couldn't find printer\n");
-
- *passer->prtstate = result;
-
- DisposPtr( (Ptr) passer );
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void OpenCallBack(integer o_state, Ptr param)
- {
- integer prErr, pres;
- PassPtr passer = (PassPtr)param;
-
- if (stopped) /* we have given up the search */
- {
- DonePrinting(-1, passer);
- return;
- }
-
- if ( o_state > 0 ) /* we are still waiting */
- {
- POPEN_Banner_Step(PrForceStatus(passer->entity)); /* spin and wait */
- Timeout(&passer->ostate, OpenCallBack, param, SPIN_TIME);
- return;
- }
-
- if ( o_state == -4096 ) /* printer busy */
- {
- POPEN_Banner_Step((StringPtr)*passer->entity); /* spin */
- passer->status.statusStr[0] = '\0'; /* Clear status string */
- if ( (pres = PAPOpen(&passer->prefnum, (EntityPtr)*passer->entity, 1,
- &passer->status, &passer->ostate)) == noErr )
- Timeout(&passer->ostate, OpenCallBack, param, SPIN_TIME);
- else
- {
- log_printf("Cannot open \"%p:%p@%p\"\n",
- *passer->entity,
- *passer->entity+((*passer->entity)[0]+1),
- *passer->entity+((*passer->entity)[0]+1)+((*passer->entity)[((*passer->entity)[0]+1)]+1));
- passer->postscript = FALSE;
- DonePrinting(pres, passer);
- }
- return;
- }
-
- POPEN_Banner_Down();
- if (o_state == noErr)
- {
- if (debugOn)
- log_printf("Open Status %d \"%p\"\n", passer->ostate, passer->status.statusStr);
-
- PRT_Banner_Up(PrForceStatus(passer->entity)); /* raise the banner */
- ReadCallBack(0, param);
-
- if (passer->postscript && accounting)
- PAPWrite(passer->prefnum, account_str, strlen(account_str), 0, &passer->wstate);
- else
- passer->wstate = 0;
- Background(&passer->wstate, WriteCallBack, param);
- }
- else
- {
- log_printf("Printer open failed; ostate %d\n", passer->ostate);
-
- PrErrorStatus(passer->entity);
- passer->postscript = FALSE;
- DonePrinting(passer->ostate, passer);
- }
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void WriteCallBack(integer w_state, Ptr param)
- {
- PassPtr passer = (PassPtr)param;
-
- if (w_state < 0)
- {
- PrErrorStatus(passer->entity);
- KillPrinting(w_state, passer);
- }
- else if (stopped)
- KillPrinting(-1, passer);
- else if (!passer->killed)
- {
- LongInt count = F_BUFF_SIZE;
- passer->feof = FSRead(passer->pfRef, &count, passer->xbuff);
- passer->count = count;
-
- if ( ( passer->feof == noErr ) || ( ( passer->feof == eofErr ) && count ) )
- { /* either there is no error or we have an end of file
- * but some bytes have been read */
- if (debugOn)
- log_printf("Sending %d Bytes\n", passer->count);
-
- PAPWrite(passer->prefnum, passer->xbuff, passer->count, 0, &passer->wstate);
- passer->prt_bytes+=count;
-
- PRT_Banner_PCent( passer->prt_bytes, passer->prt_size , PrStatus(passer->entity) );
-
- Background(&passer->wstate, WriteCallBack, param);
- return;
- }
- }
-
- PRT_Banner_PCent( passer->prt_size, passer->prt_size , PrStatus(passer->entity) );
- PRT_Banner_Down();
- PSTAT_Banner_Up(PrForceStatus(passer->entity));
-
- if (debugOn)
- log_printf("%ld Bytes sent\n", passer->prt_bytes);
-
- /* Exchange EOF messages, then close */
- if (passer->postscript && accounting)
- PAPWrite(passer->prefnum, account_str, strlen(account_str), 1, &passer->wstate);
- else
- PAPWrite(passer->prefnum, NIL, 0, 1, &passer->wstate);
-
- Timeout(&passer->wstate, WEOFCallBack, param, SPIN_TIME);
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void WEOFCallBack(integer w_state, Ptr param)
- {
- PassPtr passer = (PassPtr)param;
-
- if (stopped) KillPrinting(-1, passer);
- else if (w_state > 0) /* we are still waiting */
- {
- PSTAT_Banner_Step(PrStatus(passer->entity));
- if (!passer->killed)
- {
- Timeout(&passer->wstate, WEOFCallBack, param, SPIN_TIME);
- return;
- }
- }
-
- passer->weof = TRUE;
- if (passer->wstate < 0)
- passer->last_error = passer->wstate;
-
- KillBackground(passer->read_task);
- passer->read_task = Timeout(&passer->rstate, REOFCallBack, param, SPIN_TIME);
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static void ReadProcess(PassPtr passer)
- {
- char *substr = "%[ pagecount: ", *str;
- LongInt pagecount;
-
- if (passer->rstate < 0)
- PrErrorStatus(passer->entity);
- else if ( passer->rsize > 0 )
- {
- passer->rbuff[passer->rsize] = 0;
-
- if ( str = strstr(passer->rbuff, substr) ) /* look for the "%[ pagecount: " substring */
- {
- str += strlen(substr);
- if (sscanf(str, " %ld", &pagecount) > 0)
- {
- if (passer->startpages < 0) passer->startpages = pagecount;
- else passer->endpages = pagecount;
- }
- }
- else
- {
- log_printf("%s", passer->rbuff);
- LogError(passer->rbuff, passer->elog);
- }
- }
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void ReadCallBack(integer r_state, Ptr param)
- {
- PassPtr passer = (PassPtr)param;
-
- if (stopped) KillPrinting(-1, passer);
-
- ReadProcess(passer);
-
- /* if last PAPRead finished, try another. */
- if (!passer->killed && !passer->reof)
- {
- PAPRead(passer->prefnum, passer->rbuff, &passer->rsize, &passer->reof, &passer->rstate);
- passer->read_task = Background(&passer->rstate, ReadCallBack, param);
- }
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void REOFCallBack(integer r_state, Ptr param)
- {
- PassPtr passer = (PassPtr)param;
-
- if (stopped) KillPrinting(-1, passer);
- else if ( r_state > 0 )
- {
- PSTAT_Banner_Step(PrStatus(passer->entity));
- if (!passer->killed)
- {
- passer->read_task = Timeout(&passer->rstate, REOFCallBack, param, SPIN_TIME);
- return;
- }
- else
- passer->reof = TRUE;
- }
- else
- ReadProcess(passer);
-
- if (!passer->reof)
- {
- if (PAPRead(passer->prefnum, passer->rbuff, &passer->rsize, &passer->reof, &passer->rstate) == noErr)
- passer->read_task = Timeout(&passer->rstate, REOFCallBack, param, SPIN_TIME);
- return;
- }
-
- DonePrinting(passer->last_error, passer);
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
-
- static LongInt next_stat = 0;
- static PAPStatusRec status;
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static StringPtr PrStatus(Handle entity)
- {
- AddrBlock node;
-
- if (Ticks < next_stat)
- return NIL;
-
- next_stat = Ticks + 1200; /* every 20 seconds */
- status.statusStr[0] = '\0'; /* Clear status string */
- node.aNet = 0;
- node.aNode = 0;
- node.aSocket = 0;
-
- PAPStatus((EntityPtr)*entity, &status, &node);
-
- return status.statusStr;
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static StringPtr PrErrorStatus(Handle entity)
- {
- StringPtr tmp;
- next_stat = 0; /* to force an update */
- tmp = PrStatus(entity);
- next_stat = 0; /* to force an update next time */
-
- return tmp;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- StringPtr PrinterStatus(StringPtr printer)
- {
- StringPtr tmp;
- Handle entity;
-
- entity = GenerateEntity(printer);
-
- next_stat = 0; /* to force an update */
- tmp = PrStatus(entity);
- next_stat = 0; /* to force an update next time */
-
- HUnlock(entity);
- DisposHandle(entity);
-
- return tmp;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static StringPtr PrForceStatus(Handle entity)
- {
- next_stat = 0; /* to force an update */
- return PrStatus(entity);
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static Str255 aPrName;
-
- StringPtr GetPRName(void);
- StringPtr GetPRName()
- {
- integer LWref;
- integer wdRef;
- LongInt wdID;
- integer vol;
- SignedByte state;
- extern Str255 LaserWriterName;
-
- Handle entHndl;
-
- GetWDir(&wdRef, &wdID, &vol);
- SetExtnsFolder();
-
- if ( (LWref = OpenResFile(LaserWriterName)) == -1 )
- {
- SetWDir(wdRef, wdID, vol);
- return NIL;
- }
-
- if ( ( entHndl = GetResource('PAPA', -8192) ) == NIL || ResError() )
- {
- CloseResFile(LWref);
- SetWDir(wdRef, wdID, vol);
- return NIL;
- }
-
- state = HGetState(entHndl);
- HLock(entHndl);
-
- psprintf(aPrName, "\"%p:%p@%p\"",
- *entHndl,
- *entHndl+((*entHndl)[0]+1),
- *entHndl+((*entHndl)[0]+1)+((*entHndl)[((*entHndl)[0]+1)]+1));
-
- HSetState(entHndl, state);
-
- CloseResFile(LWref);
- SetWDir(wdRef, wdID, vol);
-
- return aPrName;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
-
- #include <Serial.H>
- pascal OSErr RAMSDOpen(SPortSel sPort);
- pascal void RAMSDClose(SPortSel sPort);
-
- typedef struct IOPassBlock
- {
- integer *iostate;
- IOParam iorec;
- } IOPassBlock, *IOPassPtr;
-
-
- static void SerialWCallBack(integer w_state, Ptr param);
- static integer SerialWrite(integer sRef, Ptr data, integer count, integer *wstate);
- static void SWriteCallBack(integer w_state, Ptr param);
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void SerialPrint(integer xRef, Boolean postscript,
- StringPtr printer, Word params,
- Handle elog, integer *pstate)
- {
- PassPtr parms = (PassPtr)NewPtrClear(sizeof(PassBlock));
-
- *pstate = 1;
- parms->prtstate = pstate;
-
- if (debugOn)
- log_printf("new serial print file (%d)\n", parms->pfRef);
-
- RAMSDOpen(sPortA);
- parms->prefnum = aoutRefNum;
-
- parms->killed = FALSE;
- stopped = FALSE;
- parms->prt_bytes = 0L;
- parms->pfRef = xRef;
-
- SWriteCallBack(0, (Ptr)parms);
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- integer SerialWrite(integer sRef, Ptr data, integer count, integer *wstate)
- {
- IOPassPtr iop = (IOPassPtr)NewPtrClear(sizeof(IOPassBlock));
- IOParam *parm = (IOParam*)&iop->iorec;
-
- *wstate = 1;
- iop->iostate = wstate;
- parm->ioCompletion = NIL;
- parm->ioRefNum = sRef;
- parm->ioBuffer = data;
- parm->ioReqCount = count;
- parm->ioPosMode = 0;
- parm->ioPosOffset = 0;
-
- PBWrite((ParmBlkPtr)parm, TRUE);
- Background(&parm->ioResult, SerialWCallBack, (Ptr)iop);
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void SerialWCallBack(integer w_state, Ptr param)
- {
- IOPassPtr iop = (IOPassPtr)param;
- IOParam *parm = (IOParam*)&iop->iorec;
-
- *iop->iostate = w_state;
- DisposPtr((Ptr)iop);
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- void SWriteCallBack(integer w_state, Ptr param)
- {
- PassPtr parms = (PassPtr)param;
-
- if (stopped)
- KillPrinting(-1, parms);
- else if (!parms->killed)
- {
- LongInt count = F_BUFF_SIZE;
- parms->feof = FSRead(parms->pfRef, &count, parms->xbuff);
- parms->count = count;
-
- if ( ( parms->feof == noErr ) || ( ( parms->feof == eofErr ) && parms->count ) )
- { /* either there is no error or we have an end of file
- * but some bytes have been read */
- if (debugOn)
- log_printf("Sending %ld Bytes\n", parms->count);
-
- SerialWrite(parms->prefnum, parms->xbuff, parms->count, &parms->wstate);
- parms->prt_bytes+=parms->count;
-
- Background(&parms->wstate, SWriteCallBack, (Ptr)parms);
- return;
- }
- }
-
- if (debugOn)
- log_printf("%ld Bytes sent\n", parms->prt_bytes);
-
- FSClose(parms->pfRef);
- RAMSDClose(sPortA);
-
- *parms->prtstate = 0;
-
- DisposPtr((Ptr)parms);
- }
-